package com.madeinhk.english_chinesedictionary;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.LeadingMarginSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import com.madeinhk.model.AppPreference;
import com.madeinhk.model.ECDictionary;
import com.madeinhk.model.Favourite;
import com.madeinhk.model.Word;
import com.madeinhk.utils.Analytics;
import com.madeinhk.view.LevelIndicator;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.greenrobot.event.EventBus;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DictionaryFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class DictionaryFragment extends Fragment implements TextToSpeech.OnInitListener {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_WORD = "word";
private static final String TAG = DictionaryFragment.class.getName();
private TextView mWordTextView;
private TextView mDetailTextView;
private TextView mPhoneticTextView;
private LevelIndicator mCommonnessBar;
private CoordinatorLayout mRootView;
private ImageButton mPronounceButton;
private TextToSpeech mTts;
private ECDictionary mECDictionary;
private Word mWord;
private Context mContext;
private int mAccentColor;
private FloatingActionButton mFavButton;
private Typeface sNotoFont;
public DictionaryFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param word Word to be queried
* @return A new instance of fragment DictionaryFragment.
*/
public static DictionaryFragment newInstance(String word) {
DictionaryFragment fragment = new DictionaryFragment();
if (!TextUtils.isEmpty(word)) {
Bundle args = new Bundle();
args.putString(ARG_WORD, word);
fragment.setArguments(args);
}
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mAccentColor = getResources().getColor(R.color.colorAccent);
mECDictionary = new ECDictionary(mContext);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
setHasOptionsMenu(true);
initTts();
String searchWord = null;
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
searchWord = savedInstanceState.getString(SearchManager.QUERY);
} else {
if (getArguments() != null) {
searchWord = getArguments().getString(ARG_WORD);
} else {
String lastWord = AppPreference.getKeyLastWord(mContext);
if (!TextUtils.isEmpty(lastWord)) {
searchWord = lastWord;
}
}
}
executeQueryTask(searchWord);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mContext = activity.getApplicationContext();
}
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_dictionary, container, false);
mRootView = (CoordinatorLayout) view.findViewById(R.id.rootLayout);
mPronounceButton = (ImageButton) view.findViewById(R.id.pronounce);
mWordTextView = (TextView) view.findViewById(R.id.word);
mPhoneticTextView = (TextView) view.findViewById(R.id.phonetic_string);
mDetailTextView = (TextView) view.findViewById(R.id.detail);
if (sNotoFont == null) {
sNotoFont = Typeface.createFromAsset(mContext.getAssets(), "NotoSans-Regular.ttf");
}
mDetailTextView.setTypeface(sNotoFont);
mCommonnessBar = (LevelIndicator) view.findViewById(R.id.commonness_bar);
mCommonnessBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int stringResId = R.string.common_word;
switch (mCommonnessBar.getLevel()) {
case 0:
stringResId = R.string.very_rare_word;
break;
case 1:
stringResId = R.string.rare_word;
break;
case 2:
stringResId = R.string.medium_word;
break;
case 3:
stringResId = R.string.common_word;
break;
case 4:
stringResId = R.string.very_common_word;
break;
}
Snackbar.make(mRootView, stringResId, Snackbar.LENGTH_LONG).show();
}
});
mFavButton = (FloatingActionButton) view.findViewById(R.id.fav_button);
mFavButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Favourite fav = Favourite.fromWord(mWord);
boolean isFav = fav.isExists(mContext);
if (isFav) {
fav.delete(mContext);
} else {
fav.save(mContext);
}
updateFavFab(mWord);
}
});
return view;
}
private void initTts() {
mTts = new TextToSpeech(mContext,
this // TextToSpeech.OnInitListener
);
}
// Implements TextToSpeech.OnInitListener.
public void onInit(int status) {
// status can be either TextToSpeech.SUCCESS or TextToSpeech.ERROR.
if (status == TextToSpeech.SUCCESS) {
// Set preferred language to US english.
// Note that a language may not be available, and the result will indicate this.
int result = mTts.setLanguage(Locale.US);
// Try this someday for some interesting results.
// int result mTts.setLanguage(Locale.FRANCE);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
// Language data is missing or the language is not supported.
Log.e(TAG, "Language is not available.");
} else {
// Check the documentation for other possible result codes.
// For example, the language may be available for the locale,
// but not for the specified country and variant.
mPronounceButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mTts.speak(mWord.mWord, TextToSpeech.QUEUE_FLUSH, null);
}
});
}
} else {
// Initialization failed.
Log.e(TAG, "Could not initialize TextToSpeech.");
}
}
@Override
public void onDestroy() {
// Don't forget to shutdown!
if (mTts != null) {
mTts.stop();
mTts.shutdown();
}
super.onDestroy();
}
private void executeQueryTask(final String query) {
new AsyncTask<String, Void, Word>() {
@Override
protected Word doInBackground(String... params) {
String query = params[0];
return mECDictionary.lookup(query);
}
@Override
protected void onPostExecute(Word word) {
if (isAdded()) {
buildHtmlFromDictionary(query, word);
}
}
}.execute(query);
}
private void appendStyled(SpannableStringBuilder builder, String str, Object... spans) {
builder.append(str);
for (Object span : spans) {
builder.setSpan(span, builder.length() - str.length(), builder.length(), Spanned
.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
private void boldKeyWord(SpannableStringBuilder builder, String str, String keyword) {
String patternString = "\\b" + keyword + "\\b";
Pattern boldKeyWordPattern = Pattern.compile(patternString);
Matcher boldKeyWordMatcher = boldKeyWordPattern.matcher(str);
while (boldKeyWordMatcher.find()) {
int start = builder.length() - str.length() + boldKeyWordMatcher.start();
int end = start + keyword.length();
builder.setSpan(new android.text.style.StyleSpan
(Typeface.BOLD), start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
private void updateFavFab(Word word) {
if (word != null) {
Favourite favourite = Favourite.fromWord(word);
boolean alreadyMarked = favourite.isExists(mContext);
mFavButton.setImageResource((alreadyMarked) ? R.drawable.ic_favorite_white_48dp : R
.drawable.ic_favorite_border_white_48dp);
mFavButton.show();
} else {
mFavButton.hide();
}
}
final static int INDENTATION_MEANING_LEFT = 50;
final static int INDENTATION_EXAMPLE_LEFT = 130;
private void buildHtmlFromDictionary(String query, Word word) {
mWord = word;
updateFavFab(word);
if (word != null) {
Analytics.trackFoundWord(getActivity(), word.mWord);
mWordTextView.setText(word.mWord);
if (!TextUtils.isEmpty(mWord.mPhoneticString)) {
mPhoneticTextView.setText(mWord.mPhoneticString);
}
if (mWord.mDifficulty > 0) {
mCommonnessBar.setVisibility(View.VISIBLE);
mCommonnessBar.setLevel((5 - mWord.mDifficulty));
} else {
mCommonnessBar.setVisibility(View.GONE);
}
List<Word.TypeEntry> typeEntries = word.mTypeEntry;
SpannableStringBuilder builder = new SpannableStringBuilder();
int prevType = -1;
boolean firstEntry = true;
for (Word.TypeEntry typeEntry : typeEntries) {
if (prevType != typeEntry.mType) {
if (!firstEntry) {
builder.append("\n");
}
firstEntry = false;
appendStyled(builder, typeEntry.getTypeDescription() + "\n",
new ForegroundColorSpan(mAccentColor));
prevType = typeEntry.mType;
}
appendStyled(builder, "• " + typeEntry.mMeaning + "\n", new LeadingMarginSpan
.Standard(INDENTATION_MEANING_LEFT, INDENTATION_EXAMPLE_LEFT));
if (!TextUtils.isEmpty(typeEntry.mEngExample)) {
appendStyled(builder, typeEntry.mEngExample + "\n", new LeadingMarginSpan
.Standard(INDENTATION_EXAMPLE_LEFT));
boldKeyWord(builder, typeEntry.mEngExample + "\n", word.mWord);
}
if (!TextUtils.isEmpty(typeEntry.mChiExample)) {
appendStyled(builder, typeEntry.mChiExample + "\n",
new LeadingMarginSpan.Standard(INDENTATION_EXAMPLE_LEFT));
}
}
mDetailTextView.setText(builder);
mPronounceButton.setVisibility(View.VISIBLE);
mPhoneticTextView.setVisibility(View.VISIBLE);
AppPreference.saveLastWord(mContext, word.mWord);
} else {
Analytics.trackNotFoundWord(getActivity(), query);
mWordTextView.setText("No such word :(");
mCommonnessBar.setVisibility(View.GONE);
mDetailTextView.setText("");
mPronounceButton.setVisibility(View.GONE);
mPhoneticTextView.setVisibility(View.GONE);
}
}
@Override
public void onCreateOptionsMenu(
Menu menu, MenuInflater inflater) {
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mWord != null) {
outState.putString(SearchManager.QUERY, mWord.mWord);
}
}
public static class UpdateWordEvent {
public String mWord;
public UpdateWordEvent(String word) {
mWord = word;
}
}
public void onEvent(UpdateWordEvent event) {
String word = event.mWord;
if (TextUtils.isEmpty(word)) {
word = AppPreference.getKeyLastWord(mContext);
}
if (!word.equals(mWord)) {
executeQueryTask(word);
}
}
}